<?php

declare(strict_types=1);

namespace App\Service;

use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use App\Library\Common;
use Hyperf\DbConnection\Db;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
use Hyperf\Di\Annotation\Inject;

/**
 * 用户收货地址管理
 * Class FlyAddressService
 * @package App\Service
 */
class FlyAddressService extends BaseService
{

    /**
     * @Inject
     * @var ValidatorFactoryInterface
     */
    private $validation;

    /**
     * @Inject
     * @var AreainfoService
     */
    private $areainfo;

    /**
     * 获取我的收货地址
     * @param int $user_id
     * @return array
     */
    public function getMyAddress(int $user_id): array
    {
        $address_fields = ['id', 'is_default', 'street_id', 'street_str', 'address_info', 'link_name', 'phone', 'lat', 'lng'];
        $address = $this->getModelInstance()->where([
            'user_id' => $user_id,
            'delete_time' => 0
        ])->select($address_fields)->get();
        $list = [];
        if (!empty($address)) {
            $list = $address->toArray();
            foreach ($list as &$item) {
                $item['address_arr'] = $this->areainfo->getFullAddress($item['street_id']);
            }
        }
        return $list;
    }

    /**
     * 获取收货地址
     * @param int $user_id
     * @param int $addr_id
     * @return array
     */
    public function getMyAddressById(int $user_id, int $addr_id): array
    {
        $address = $this->getModelInstance()->where('user_id', '=', $user_id)->find($addr_id);
        $list = [];
        if (!empty($address)) {
            $list = $address->toArray();
            if ($list['delete_time'] > 0) {
                return [];
            }
        } else {
            return $list;
        }
        $list['address_arr'] = $this->areainfo->getFullAddress($list['street_id']);
        return $list;
    }

    /**
     * 验证并返回有效地址设置参数
     * @param array $params
     * @return array
     */
    public function verifyGetData(array $params): array
    {
        $get_filtered_data = $this->getFilterData($params);
        $v_res = $this->validation->make($get_filtered_data['params'], $get_filtered_data['filter']);
        $res = true;
        $msg = '';
        $data = [];
        // 验证失败
        if ($v_res->fails()) {
            $msg = $v_res->errors()->first();
            $res = false;
        } else {
            $data = $get_filtered_data['params'];
            // 验证地区
            $address = $this->areainfo->getAreainfo($data['street_id'], true);
            if (empty($address) || $address['level'] !== 5) {
                $msg = "未选择街道";
                $res = false;
            }
            // 获取街道完整名称
            $street_arr = array_column($this->areainfo->getFullAddress($address['id']), 'name');
            $data['street_str'] = implode('', $street_arr);
            $locate = Common::getAddressLocation($data['street_str'] . $data['address_info']);
            $data['lat'] = $locate['lat'] ?? 0;
            $data['lng'] = $locate['lng'] ?? 0;
        }
        return [
            'msg' => $msg,
            'res' => $res,
            'data' => $data
        ];
    }

    /**
     * 保存地址
     * @param array $data
     * @return int  地址ID
     */
    public function setAddress(array $data): int
    {
        if (!empty($data['id'])) {
            $instance = $this->getModelInstance()->where(['user_id' => $data['user_id']])->find($data['id']);
            // 无法修改 不存在
            if (empty($instance)) {
                return 0;
            }
        } else {
            $instance = $this->getModelInstance();
        }
        Db::beginTransaction();
        try {
            foreach ($data as $k => $val) {
                $instance->$k = $val;
            }
            if (!empty($data['id'])) {
                $instance->update_time = time();
            } else {
                $instance->create_time = time();
            }
            if (!$instance->save()) {
                return 0;
            }

            if (isset($data['is_default']) && $data['is_default'] == 1) {
                $this->resetDefault($data['user_id'], $instance->id);
            }

        } catch (\Throwable $exception) {
            echo $exception->getMessage();
            throw new BusinessException(ErrorCode::NORMAL_ERROR, $exception->getMessage());
            Db::rollBack();
            return 0;
        }
        Db::commit();
        return $instance->id;
    }

    /**
     * 取消原来默认地址
     * @param int $user_id
     * @param int $id
     */
    public function resetDefault(int $user_id, int $id): void
    {
        $this->getModelInstance()->where(['user_id' => $user_id, 'is_default' => 1])->where('id', '<>', $id)->update(['is_default' => 0]);
    }

    /**
     * 删除地址
     * @param array $params
     * @return bool
     */
    public function delAddress(array $params): bool
    {
        if (empty($params['user_id']) || empty($params['id'])) {
            return false;
        }
        $instance = $this->getModelInstance()->query(true)->find($params['id']);
        if (empty($instance) || $instance->user_id != $params['user_id']) return false;
        $instance->delete_time = time();
        if (!$instance->save()) {
            return false;
        }
        return true;
    }

    /**
     * 获取过滤参数
     * @param array $params
     * @return array
     */
    public function getFilterData(array $params): array
    {
        $filter_arr = ['id', 'user_id', 'is_default', 'street_id', 'address_info', 'link_name', 'phone'];

        foreach ($params as $pk => $param) {
            if (!in_array($pk, $filter_arr)) {
                unset($params[$pk]);
            }
        }
        $filter = [
            'id' => ['integer', 'nullable'],
            'user_id' => ['required', 'integer'],
            'is_default' => ['integer', 'nullable'],
            'street_id' => ['required', 'integer'],
            'address_info' => ['required', 'max:255'],
            'link_name' => ['required', 'max:64'],
            'phone' => ['required']
        ];
        return ['filter' => $filter, 'params' => $params];
    }

}